package com.zhijian.medical.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Sets;
import com.zhijian.medical.dao.local.PcrHskzyqMapper;
import com.zhijian.medical.entity.po.*;
import com.zhijian.medical.entity.vo.request.*;
import com.zhijian.medical.entity.vo.response.*;
import com.zhijian.medical.enums.*;
import com.zhijian.medical.holder.CurrentUserHolder;
import com.zhijian.medical.service.*;
import com.zhijian.medical.util.AssertUtil;
import com.zhijian.medical.util.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 荧光PCR-核酸扩增一区业务处理层
 *
 * @author HCG
 * @version: 1.0
 * @date 2022-08-30 15:34:31
 */
@Slf4j
@Service
public class PcrHskzyqServiceImpl implements PcrHskzyqService {

    @Autowired
    private PcrHskzyqMapper mapper;

    @Autowired
    private PcrKzyService pcrKzyService;

    @Autowired
    private PcrService pcrService;

    @Autowired
    private ExperimentProcessSampleService experimentProcessSampleService;

    @Autowired
    private ExperimentProcessSampleLogService experimentProcessSampleLogService;

    @Autowired
    private PcrResultService pcrResultService;

    @Autowired
    private PcrResultDetailService pcrResultDetailService;

    @Override
    public PcrHskzyq selectById(Long id) {
        return mapper.selectByPrimaryKey(id);
    }

    @Override
    public PcrHskzyq selectByPcrId(Long pcrId) {
        return mapper.selectByPcrId(pcrId);
    }

    @Override
    public PcrHskzyqVo selectVoById(Long id) {
        return mapper.selectVoById(id);
    }

    @Override
    public PcrHskzyqVo selectVoByPcrId(Long pcrId) {
        PcrHskzyqVo pcrHskzyqVo = mapper.selectVoByPcrId(pcrId);
        if (Objects.isNull(pcrHskzyqVo)) {
            return null;
        }
        Pcr pcr = pcrService.selectById(pcrId);
        if (Objects.isNull(pcr)) {
            return null;
        }
        Byte type = pcr.getType();
        PcrTypeEnum pcrTypeEnum = PcrTypeEnum.getByCode(type.intValue());
        AssertUtil.notNull(pcrTypeEnum, "类型非法");
        assert pcrTypeEnum != null;
        switch (pcrTypeEnum) {
            case KNB:
                pcrHskzyqVo.setResult(pcr.getStatus() > PcrKnbStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getCode().byteValue() : AllExperimentationStepStatusEnum.UN_END.getCode().byteValue());
                pcrHskzyqVo.setResultStr(pcr.getStatus() > PcrKnbStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getDesc() : AllExperimentationStepStatusEnum.UN_END.getDesc());
                break;
            case GW_HPV:
                break;
            case FA_5:
                break;
            case JAK2:
                break;
            case PIK3CA:
                break;
            case COV:
                pcrHskzyqVo.setResult(pcr.getStatus() > PcrCovStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getCode().byteValue() : AllExperimentationStepStatusEnum.UN_END.getCode().byteValue());
                pcrHskzyqVo.setResultStr(pcr.getStatus() > PcrCovStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getDesc() : AllExperimentationStepStatusEnum.UN_END.getDesc());
                break;
            default:
                pcrHskzyqVo.setResult(pcr.getStatus() > PcrKnbStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getCode().byteValue() : AllExperimentationStepStatusEnum.UN_END.getCode().byteValue());
                pcrHskzyqVo.setResultStr(pcr.getStatus() > PcrKnbStatusEnum.HSKZYQ.getCode().byteValue() ?
                        AllExperimentationStepStatusEnum.END.getDesc() : AllExperimentationStepStatusEnum.UN_END.getDesc());
                break;
        }
        //扩增仪数据
        List<PcrOfKzyVo> pcrOfKzyVos = pcrKzyService.selectPcrOfKzyVoByPcrId(pcrId);
        pcrHskzyqVo.setKzyList(pcrOfKzyVos);
        return pcrHskzyqVo;
    }

    @Override
    public void deleteById(Long id) {
        mapper.deleteByPrimaryKey(id);
    }

    @Override
    public void deleteByPcrId(Long pcrId) {
        mapper.deleteByPcrId(pcrId);
    }

    @Override
    public Long insert(PcrHskzyq pcrHskzyq) {
        Date now = new Date();
        pcrHskzyq.setCreateTime(now);
        pcrHskzyq.setUpdateTime(now);
        pcrHskzyq.setHskzsystmqj(StatusEnum.UN_NORMAL.getCode().byteValue());
        pcrHskzyq.setJgpdsyh1(StatusEnum.UN_NORMAL.getCode().byteValue());
        pcrHskzyq.setJgpdsyh2(StatusEnum.UN_NORMAL.getCode().byteValue());
        pcrHskzyq.setJgpdsyh3(StatusEnum.UN_NORMAL.getCode().byteValue());
        return mapper.insert(pcrHskzyq) > 0 ? pcrHskzyq.getId() : 0L;
    }

    @Override
    public boolean update(PcrHskzyq pcrHskzyq) {
        Date now = new Date();
        pcrHskzyq.setUpdateTime(now);
        return mapper.updateByPrimaryKey(pcrHskzyq) != 0;
    }

    @Override
    public Integer count(PcrHskzyqSearchVo pcrHskzyqSearchVo) {
        return mapper.count(pcrHskzyqSearchVo);
    }

    @Override
    public List<PcrHskzyqVo> selectList(PcrHskzyqSearchVo pcrHskzyqSearchVo) {
        return mapper.selectList(pcrHskzyqSearchVo);
    }

    @Override
    public Page<PcrHskzyqVo> selectPage(PcrHskzyqSearchVo pcrHskzyqSearchVo) {
        //先直接查总数
        int count = count(pcrHskzyqSearchVo);
        //分页
        Page<PcrHskzyqVo> page = new Page<>(true, count, pcrHskzyqSearchVo.getPageNum(), pcrHskzyqSearchVo.getPageSize());
        pcrHskzyqSearchVo.setStartIndex(page.getStartIndex());
        page.setPage(true);
        page.setTotalCount(count);
        List<PcrHskzyqVo> responseVos = this.selectList(pcrHskzyqSearchVo);
        page.setData(responseVos);
        return page;
    }

    @Transactional(rollbackFor = Exception.class, value = "localTransactionManager")
    @Override
    public boolean saveOrUpdate(PcrHskzyqSaveOrUpdateVo pcrHskzyqSaveOrUpdateVo) {
        Long pcrId = pcrHskzyqSaveOrUpdateVo.getPcrId();
        Pcr pcr = pcrService.selectById(pcrId);
        AssertUtil.notNull(pcr, "此实验不存在或者已被删除");
        List<PcrKzySaveOrUpdateVo> pcrHskzyqSaveOrUpdateVoKzyList = pcrHskzyqSaveOrUpdateVo.getKzyList();
        //去重后的扩增仪设备id列表
        List<Long> deviceIds = pcrHskzyqSaveOrUpdateVoKzyList.stream().map(PcrKzySaveOrUpdateVo::getDeviceId).distinct().collect(Collectors.toList());
        AssertUtil.check(deviceIds.size() != pcrHskzyqSaveOrUpdateVoKzyList.size(), "添加的扩增仪不允许重复");
        Pcr updateParam = Pcr.builder()
                .id(pcrId)
                .endTime(new Date())
                .build();

        if (pcr.getStatus() < PcrKnbStatusEnum.END.getCode().byteValue()) {
            //将实验的状态修改
            updateParam.setStatus(PcrKnbStatusEnum.END.getCode().byteValue());
        }
        pcrService.updateByPrimaryKeySelective(updateParam);

        //要保存的扩增仪区域id列表
        List<Long> saveOrUpdateKzyIds = pcrHskzyqSaveOrUpdateVoKzyList.stream().map(PcrKzySaveOrUpdateVo::getId).collect(Collectors.toList());
        //已经存在的扩增仪区域
        List<PcrKzyVo> oldPcrHskzyqVos = pcrKzyService.selectList(PcrKzySearchVo.builder()
                .pcrId(pcrId)
                .build());
        if (CollectionUtil.isNotEmpty(oldPcrHskzyqVos)) {
            //如果有已经存在的扩增仪区域，把id组装起来
            List<Long> oldIds = oldPcrHskzyqVos.stream().map(PcrKzyVo::getId).collect(Collectors.toList());
            //计算两者的差集
            Collection<Long> delIds = CollectionUtils.subtract(oldIds, saveOrUpdateKzyIds);
            if (CollectionUtil.isNotEmpty(delIds)) {
                //删除掉已经没有保存的
                delIds.forEach(delId -> {
                    pcrKzyService.deleteById(delId);
                    pcrResultService.deleteByPcrKzyId(delId);
                    pcrResultDetailService.deleteByPcrKzyId(delId);
                });
            }
        }

        PcrHskzyq oldPcrHskzyq = this.selectByPcrId(pcrId);
        PcrHskzyq dbParam = new PcrHskzyq();
        BeanUtils.copyProperties(pcrHskzyqSaveOrUpdateVo, dbParam);
        if (Objects.isNull(oldPcrHskzyq)) {
            this.insert(dbParam);
        } else {
            dbParam.setId(oldPcrHskzyq.getId());
            this.update(dbParam);
        }

        //不合格的分子病理号id列表
        Set<Long> bhgSampleIds = Sets.newHashSet();
        if (CollectionUtil.isNotEmpty(pcrHskzyqSaveOrUpdateVoKzyList)) {
            //再操作扩增仪数据
            pcrHskzyqSaveOrUpdateVoKzyList.forEach(p -> {
                p.setPcrId(pcrId);
                PcrKzy oldPcrKzy = pcrKzyService.selectByPcrIdAndDeviceId(pcrId, p.getDeviceId());
                PcrKzy pcrKzyDbParam = new PcrKzy();
                BeanUtils.copyProperties(p, pcrKzyDbParam);
                Long pcKzyId;
                if (Objects.isNull(oldPcrKzy)) {
                    //新增扩增仪
                    pcKzyId = pcrKzyService.insert(pcrKzyDbParam);
                } else {
                    //编辑
                    pcrKzyDbParam.setId(oldPcrKzy.getId());
                    pcrKzyDbParam.setLcbbbshkzwzData(oldPcrKzy.getLcbbbshkzwzData());
                    pcrKzyService.update(pcrKzyDbParam);
                    pcKzyId = oldPcrKzy.getId();
                }
                if (pcrKzyDbParam.getJgpdyxsnzksfwr() == StatusEnum.NORMAL.getCode().byteValue() || pcrKzyDbParam.getJgpdyxsnzksfzk() == StatusEnum.UN_NORMAL.getCode().byteValue()) {
                    //如果阴性室内质控为是，或者阳性室内质控为否，则所有样本不合格
                    List<PcrResultVo> pcrResultVos = pcrResultService.selectList(PcrResultSearchVo.builder()
                            .pcrKzyId(pcKzyId)
                            .build());

                    //外面的不合格样本列表，通过阴性室内质控与阳性室内质控来判断
                    Set<ExperimentProcessSample> bhgOutList = Sets.newHashSet();

                    if (CollectionUtil.isNotEmpty(pcrResultVos)) {
                        pcrResultVos.forEach(pcrResultVo -> {
                            //分子病理号
                            String blh = pcrResultVo.getBlh();
                            ExperimentProcessSample experimentProcessSample = experimentProcessSampleService.selectByFzblh(blh);
                            if (Objects.nonNull(experimentProcessSample) && Objects.equals(experimentProcessSample.getExperimentProcessId(), pcrId)) {
                                //如果样本存在，而且正确存在于这个实验当中，就修改状态到 核酸提取完成
                                bhgOutList.add(experimentProcessSample);
                                bhgSampleIds.add(experimentProcessSample.getId());
                            }
                        });

                    }
                    if (CollectionUtil.isNotEmpty(bhgOutList)) {
                        bhgOutList.forEach(experimentProcessSample -> experimentProcessSampleService.createNewFromBhg(experimentProcessSample, pcr));
                    }
                }
            });
        }
        List<ExperimentProcessSampleVo> experimentProcessSampleVos = experimentProcessSampleService.selectList(ExperimentProcessSampleSearchVo.builder()
                .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                .experimentProcessId(pcrId)
                .build());
        List<ExperimentProcessSampleLog> collect1 = experimentProcessSampleVos.stream().map(e -> {
            if (bhgSampleIds.contains(e.getId())) {
                return null;
            }
            return ExperimentProcessSampleLog.builder()
                    .sampleId(e.getId())
                    .fishId(pcrId)
                    .mainType(ExperimentTypeEnum.PCR.getCode().byteValue())
                    .op(String.format("%s%s-%s", pcr.getName(), pcr.getProcessNumber(), PcrKnbStatusEnum.HSKZYQ.getDesc()))
                    .opUser(CurrentUserHolder.getUser().getName())
                    .build();
        }).filter(Objects::nonNull).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(collect1)) {
            //保存样本日志
            experimentProcessSampleLogService.saveBatch(collect1);
        }
        return true;
    }

}